/*
 * Adam Blackwell
 * ada2358@ccs.neu.edu
 */

import java.util.Iterator;

/***********************************************************************
 * AutonomousEnemy class
 * 
 * Implements a ship that can move and attack on its own
 *
 * Signature:
 *  public static AutonomousEnemy create (String name, Coord position, int energy);
 *  public void install ();
 *  public void destroy ();
 *  public Coord position ();
 *  public String name ();
 *  public void report (String message);
 *  public void changePosition (Coord target);
 *  public boolean isOrbitable ();
 *  public void takeDamage (int damage);
 *  public abstract char display ();
 *  public abstract String toString ();
 *  public int energy ();
 *  public void move (int dx, int dy) {
 ***********************************************************************/
/**
 * AutonomousEnemy:
 * @author Adam
 */
public class AutonomousEnemy extends Ship implements Observer<Integer> {
  /**
   * Protected Constructor:
   * @param n
   * @param p
   * @param e
   */
  protected AutonomousEnemy(String n, Coord p, int e) {
    super(n, p, e);
  }
  
  /**
   * Default Creator:
   * @param n
   * @param p
   * @param e
   * @return
   */
  public static AutonomousEnemy create(String n, Coord p, int e) {
    AutonomousEnemy sh = new AutonomousEnemy(n, p, e);
    sh.install();
    return sh;
  }
  
  /*
   * (non-Javadoc)
   * @see Artifact#install()
   * @author Adam
   */
  public void install() {
    // If at the start create an instance.
    if (SpaceGame.clock().time() == 0) {
      Coord size = SpaceGame.map().size();
      SpaceGame.updateMap(Map.merge(Map.artifact(size.xPos(), size.yPos(), this),
                                    SpaceGame.map()));
      // Regester wth the clock.
      SpaceGame.clock().registerObserver(this);
      return;
    }
  }
  
  /*
   * (non-Javadoc)
   * @see Observer#notify(java.lang.Object)
   * @author Adam
   */
  public void notify(Integer time) {
    int rand = Util.randomNumber(4);  // If you want to try to orbit occasionally 
    if(rand == 1 || rand == 2) {      // un-comment and turn this value to 5.
      this.fire();
    } else if (rand == 3 || rand == 4) {
      this.move();
    } else if (rand == 5) {
      //this.moveAndOrbit();
    }
  }
  
  /**
   * Move:
   * @param dx
   * @param dy
   */
  public void move() {
    Coord c = this.position().add(Util.randomShift(5));
    int cost = this.position().distanceInt(c);
    if (energy() <= 0) {
      report("destroyed");
      this.destroy();
      return;
    }
    report("attempting to move to " + c);
    if (!(c.within(Coord.create(0, 0), SpaceGame.map().size().move(-1, -1)))) {
      report("target position out of bounds");
      return;
    }
    useEnergy(cost);
    Option<Artifact> target = SpaceGame.map().findArtifactByPosition(c);
    if (target.isNone()) {
      report("moved to " + c);
      changePosition(c);
      return;
    }
    // there's something at the target position
    report("emergency collision avoidance!");
    do {
      Coord shift = Util.randomShift(5);
      c = c.add(shift);
      useEnergy(5);
    } while (!c.within(Coord.create(0, 0), SpaceGame.map().size().move(-1, -1))
             || !SpaceGame.map().findArtifactByPosition(c).isNone());
    report("moved to " + c);
    changePosition(c);
  }
  
  /**
   * Fires on the position that is dx, dy spaces away.
   * @author Adam
   * @param x
   * @param y
   */
  public void fire() {
    // Is there enough Energy:
    if (energy() < 0) {
      report("destroyed");
      this.destroy();
      return;
    }
    // Firing, uses five units of energy:
    // Target and (Potentially) Victim:
    Coord target = SpaceGame.me().position();
    Option<Artifact> victim = SpaceGame.map().findArtifactByPosition(target);
    // Use Energy:
    useEnergy(5);
    // Prints:
    report("firing to " + target.toString());
    report("energy down to " + this.energy());
    // If we hit nothing:
    if (victim.isNone()) {
      report("miss");
    // Else if we hit a Planet or Star, do nothing:
    } else if (victim.valOf().toString().startsWith("Star")
        || victim.valOf().toString().startsWith("Planet")) {
      report("direct hit on" + victim.valOf().name());
    // Else if we hit a Base or Ship, do damage:
    } else if (victim.valOf().toString().startsWith("Base") 
        || victim.valOf().toString().startsWith("Ship")) {
      report("direct hit on" + victim.valOf().name());
      victim.valOf().takeDamage(5);
    }
    // Return:
    return;
  }
  

//  /**
//   * MoveAndOrbit:
//   * Just thought this way the game might last longer.
//   * @param dx
//   * @param dy
//   */
//  public void moveAndOrbit() {
//    Iterator<Artifact> it = SpaceGame.map().iterator();
//    Artifact art;
//    do {
//      art = it.next();
//    } while (it.hasNext() && !art.isOrbitable());
//    
//    Coord c = this.position().move(art.position().xPos()-this.position().xPos()-1,
//                                   art.position().yPos()-this.position().yPos()-1);
//    int cost = this.position().distanceInt(c);
//    if (energy() <= 0) {
//      report("destroyed");
//      this.destroy();
//      return;
//    }
//    report("attempting to move to " + c);
//    if (!(c.within(Coord.create(0, 0), SpaceGame.map().size().move(-1, -1)))) {
//      report("target position out of bounds");
//      return;
//    }
//    useEnergy(cost);
//    Option<Artifact> target = SpaceGame.map().findArtifactByPosition(c);
//    if (target.isNone()) {
//      report("moved to " + c);
//      changePosition(c);
//      return;
//    }
//    // there's something at the target position
//    report("emergency collision avoidance!");
//    do {
//      Coord shift = Util.randomShift(5);
//      c = c.add(shift);
//      useEnergy(5);
//    } while (!c.within(Coord.create(0, 0), SpaceGame.map().size().move(-1, -1))
//             || !SpaceGame.map().findArtifactByPosition(c).isNone());
//    report("moved to " + c);
//    changePosition(c);
//    orbit(art);
//  }
}
